Welcome!

Packages

Package Structure

dir.create("ducksay")
setwd("ducksay")
DESCRIPTION
NAMESPACE
man/
R/
tests/
Package: ducksay
Title: Duck Say
Description: Say hello with a duck.
Version: 1.0
Authors@R: person("Carter", "Zenke", email = "carter@cs50.harvard.edu", role = c("aut", "cre", "cph"))
License: MIT + file LICENSE
# Demonstrates adding on to a license template

YEAR: ...
COPYRIGHTHOLDER: ducksay authors

devtools

Writing Tests

# Demonstrates suggesting a dependency, for testing's sake

Package: ducksay
Title: Duck Say
Description: Say hello with a duck.
Version: 1.0
Authors@R: person("Carter", "Zenke", email = "carter@cs50.harvard.edu", role = c("aut", "cre", "cph"))
License: MIT + file LICENSE
Suggests:
    testthat (>= 3.0.0)
Config/testthat/edition: 3

Notice that the package will suggest that one should have testthat version 3.0.0 or above installed. This may vary depending on the version of testthat that you’ve installed.

# Demonstrates describing behavior of `ducksay`

describe("ducksay()", {
  it("can print to the console with `cat`", {
    expect_output(cat(ducksay()))
  })
  it("can say hello to the world", {
    expect_match(ducksay(), "hello, world")
  })
})

Notice that expect_match looks for the string hello, world in the output of ducksay.

Writing R Code

# Demonstrates defining a function for a package

ducksay <- function() {
  paste(
    "hello, world",
    ">(. )__",
    " (____/",
    sep = "\n"
  )
}

NAMESPACE

# Demonstrates declaring `ducksay` accessible to package end users

export(ducksay)

This file simply makes the ducksay function available to the end user of the package.

Testing Code

# Demonstrates checking for duck in output

describe("ducksay()", {
  it("can print to the console with `cat`", {
    expect_output(cat(ducksay()))
  })
  it("can say hello to the world", {
    expect_match(ducksay(), "hello, world")
  })
  it("can say hello with a duck", {
    duck <- paste(
      ">(. )__",
      " (____/",
      sep = "\n"
    )
    expect_match(ducksay(), duck, fixed = TRUE)
  })
})

Notice how this test looks to see if a duck is represented. Additionally, notice how fixed = TRUE, as described in the lecture, prevents the test from misinterpreting some of the characters within the duck as being part of something called a regular expression. Suffice to say for now, a regular expression is not what we’d like!

Writing Documentation

We can now document how to use our function. Typically, we can type ?ducksay to see documentation. However, we have not created our documentation yet. Documentation is written in a type of language called a markup language. A markup language provides syntax for specifying the formatting of a document. *You can write your documentation by typing:

dir.create("man")
file.create("man/ducksay.Rd")

The first command creates a folder called man. The second creates our documentation file. *Modify your documentation file as follows:

# Demonstrates required markup for R documentation files

\name{ducksay}
\alias{ducksay}
\title{Duck Say}
\description{A duck that says hello.}
\usage{
ducksay()
}
\value{
A string representation of a duck saying hello to the world.
}
\examples{
cat(ducksay())
}

Notice how the name, title, description, usage, and other sections are provided. You can learn more about these elements by reading the documentation on R documentation files.

Building Packages

Updating Packages

# Demonstrates ensuring duck repeats given phrase

describe("ducksay()", {
  it("can print to the console with `cat`", {
    expect_output(cat(ducksay()))
  })
  it("can say hello to the world", {
    expect_match(ducksay(), "hello, world")
  })
  it("can say hello with a duck", {
    duck <- paste(
      ">(. )__",
      " (____/",
      sep = "\n"
    )
    expect_match(ducksay(), duck, fixed = TRUE)
  })
  it("can say any given phrase", {
    expect_match(ducksay("quack!"), "quack!")
  })
})

Notice that a new test is added that looks for “quack!”

# Demonstrates taking an argument to print

ducksay <- function(phrase = "hello, world") {
  paste(
    phrase,
    ">(. )__",
    " (____/",
    sep = "\n"
  )
}

Notice that a default phrase, “hello, world” is provided. If another phrase is provided, it will say that phrase instead.

# Demonstrates updated markup, including specifying arguments

\name{ducksay}
\alias{ducksay}
\title{Duck Say}
\description{A duck that says hello.}
\usage{
ducksay(phrase = "hello, world")
}
\arguments{
\item{phrase}{The phrase for the duck to say.}
}
\value{
A string representation of a duck saying the given phrase.
}
\examples{
cat(ducksay())
cat(ducksay("quack!"))
}

Notice that value is updated. Further, arguments is also updated. Another example is provided in examples.

We can run build again to include our modifications. This package can now be shared with others.

Using and Sharing Packages

# Demonstrates using custom package

library(ducksay)

name <- readline("What's your name? ")
greeting <- ducksay(paste("hello,", name))
cat(greeting)

Notice that this program loads ducksay. Then, the code uses this new library.

install.packages
R CMD INSTALL

Summing Up

In this lesson, you learned how to package your programs in R. Specifically, you learned about: * Packages * Package Structure * devtools * Writing Tests * Writing R Code * NAMESPACE * Testing Code * Writing Documentation * Building Packages * Updating Packages * Using and Sharing Packages

In this course, you learned many things about R and programming with R. You learned how to represent data, transform data, apply functions, tidy data, visualize data, test programs, and package programs. In all, we hope that you have found this material helpful to you. We also hope that you will take what you have learned to do great good in the world.

This was CS50’s Introduction to Programming with R.